package org.jeeasy.generate.service.impl;

import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.context.Context;
import org.jeeasy.generate.domain.GenModule;
import org.jeeasy.generate.domain.GenTable;
import org.jeeasy.generate.domain.GenTemplate;
import org.jeeasy.generate.domain.dto.GeneratorDTO;
import org.jeeasy.generate.domain.dto.NewGeneratorDTO;
import org.jeeasy.generate.generator.CaseName;
import org.jeeasy.generate.generator.TableContext;
import org.jeeasy.generate.service.GenModuleService;
import org.jeeasy.generate.service.GenTableService;
import org.jeeasy.generate.service.GenTemplateService;
import org.jeeasy.generate.service.GeneratorService;
import org.jeeasy.generate.service.vo.GenResultVo;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.StringWriter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
@Service
@RequiredArgsConstructor
public class GeneratorServiceImpl implements GeneratorService {

    final GenTableService genTableService;
    final GenTemplateService templateService;
    final GenModuleService genModuleService;

    @Override
    public List<GenResultVo> genFiles(NewGeneratorDTO model) {
        String tableId = model.getTableId();
        String moduleCode = model.getModuleCode();
        String templateType = model.getTemplateType();
        List<String> files = model.getFiles();
        List<String> templateContents = model.getTemplateContents();


        GenTable table = genTableService.getById(tableId);

        String modelName = new CaseName(table.getName().replace(moduleCode + "_", "").toLowerCase()).getCamel();
        String entityClassName = new CaseName(table.getName().toLowerCase()).getPascal();

        GenModule genModule = genModuleService.getByCode(moduleCode);
        List<GenTemplate> templates = templateService.getByType(templateType);

        Map<String, String> replaceParams = Map.of("module", modelName, "className", entityClassName);


        AtomicInteger index = new AtomicInteger();
        List<GeneratorDTO.GeneratorFile> list = templates.stream().map(template -> {
            String file = template.getName();
            //String className = template.getFileName().replace("\\{className}", entityClassName);
            GeneratorDTO.GeneratorFile generatorFile = new GeneratorDTO.GeneratorFile();
            // 模板文件名称
            String fileName = template.getFileName();
            //log.info("file ---> {}", file);

            String pkg = genModule.pkg(CaseName.toCamel(file), replaceParams);
            String path = pkg.replaceAll("\\.", "/");
            AtomicReference<String> outputName = new AtomicReference<>(path + "/" + fileName);
            replaceParams.forEach((key, value) -> outputName.set(outputName.get().replaceAll("\\{" + key + "}", value)));

            //String className = FileUtil.getName(outputName.get());
            String className = FilenameUtils.getBaseName(outputName.get());

            String templateContent = "";
            if (!CollectionUtils.isEmpty(templateContents) && templateContents.size() > index.get()) {
                templateContent = templateContents.get(index.get());
            }
            if (StrUtil.isBlank(templateContent)) {
                templateContent = template.getContent();
            }
            generatorFile.setPkg(pkg)
                    .setPath(path)
                    .setType(file)
                    .setTemplate(fileName)
                    .setTemplateType(templateType)
                    .setOutputName(outputName.get())
                    .setClassName(className)
                    .setTemplateContent(templateContent)
            ;
            if (CollectionUtils.isEmpty(table.getTableFields())) {
                genTableService.setFields(table);
            }

            index.getAndIncrement();
            return generatorFile;
        }).toList();

        TableContext tableContext = table.transfer(TableContext.class);
        tableContext.putAuthorAndFiles(table, model.getAuthor(), list);

        return list.stream().filter(item -> files.contains(item.getType())).map(item -> render(tableContext.toContext(), item)).toList();

    }

    private GenResultVo render(Context context, GeneratorDTO.GeneratorFile file) {
        StringWriter writer = new StringWriter();

        String templateContent = file.getTemplateContent();
        String type = file.getType();
        String template = file.getTemplate();
        String outputName = file.getOutputName();
        String logTag = String.format("%s: %s", type, template);

        Velocity.evaluate(context, writer, logTag, StrUtil.nullToDefault(templateContent, ""));
        return new GenResultVo(type, writer.toString(), outputName);
    }

}
